#Include ../ui/MyInputBox.ahk
#Include ./Zoom.ahk

#Include g:\AHK\git-ahk-lib\Extend.ahk

class PasteGui extends Gui {

  static _cache := Map()

  data := {
    sizeW: 0,
    sizeH: 0,
    hasShadow: false,
    hasTimestamp: false,
    zoomLevel: 0,
    createTime: ''
  }

  SetSizeW(v) => this.data.sizeW := v
  SetSizeH(v) => this.data.sizeH := v
  SetWH(w, h) {
    this.data.sizeW := w
    this.data.sizeH := h
  }
  SetHasShadow(v) => this.data.hasShadow := v
  SetHasTimestamp(v) => this.data.hasTimestamp := v
  SetZoomLevel(v) => this.data.zoomLevel := v
  SetCreateTime(time?) => this.data.createTime := time ?? FormatTime(, 'yyyyMMddHHmmss')
  SizeW => this.data.sizeW
  SizeH => this.data.sizeH
  HasShadow => this.data.hasShadow
  HasTimestamp => this.data.hasTimestamp
  ZoomLevel => this.data.zoomLevel
  CreateTime => this.data.createTime

  __New(option?) {
    guiOpt := IsSet(option)
      ? RTrim(StrReplace(cfg.guiOption ' ' option, '\s+', A_Space))
      : cfg.guiOption
    options := hit := PasteGui._cache.Get(guiOpt, '')
    opts := PasteGui._cache.Get('@' hit, '')
    if !hit {
      opts := Map()
      guiOptList := Array()
      loop parse guiOpt, A_Space {                ; normalize
        if A_LoopField[1] = '-' {
          guiOptList.Push(A_LoopField)
          opts.Set(SubStr(A_LoopField, 2), false)
        } else {
          opt := A_LoopField[1] = '+' ? SubStr(A_LoopField, 2) : A_LoopField
          guiOptList.Push('+' opt)
          opts.Set(opt, true)
        }
      }
      options := guiOptList.Join(A_Space)
      PasteGui._cache.Set(guiOpt, options)
      PasteGui._cache.Set('@' options, opts)     ; To prevent cover key
    }
    this.guiOpt := opts
    super.__New(options, A_ScriptName, this)
    this.SetZoomLevel(StretchRatio.normal)
    this.SetCreateTime(FormatTime(, 'yyyyMMddHHmmss'))
  }

  OnDestroy(*) {
    if this.HasProp('content') {
      DllCall('DeleteDC', 'ptr', this.content.DC)
    }
    this.Destroy()
  }

  RegisterEvent() {
    this.GetPos(&x, &y, &w, &h)
    this.SetWH(w, h)
    this.OnEvent('ContextMenu', OnCM)
    text := this.AddText('xs x0 y0 w' w ' h' h)
    text.OnEvent('Click', 'MoveWin')      ; PostMessage is not suitable for this task
    text.OnEvent('DoubleClick', (*) => this.OnDestroy())
    this.eProxy := text
  }

  HasOpt(opt) {
    return this.guiOpt.Has(opt) && this.guiOpt.Get(opt)
  }

  MoveWin(*) {
    MouseGetPos(&px, &py)
    WinGetPos(&wx, &wy, , , 'A')
    this.GetPos(&wx, &wy)
    dx := wx - px, dy := wy - py
    While GetKeyState("LButton", "P") {
      MouseGetPos(&nx, &ny)
      this.Move(nx + dx, ny + dy)
    }
  }

}

OnCM(obj, ctrlObj, item, isR, x, y) {
  m := Menu()
  m.Add '关闭', (*) => obj.OnDestroy()
  m.Add '关闭全部', (*) => ClearAll()
  m.Add
  m.Add '销毁', (*) => DestroyGui(obj)
  m.Add
  sm := Menu()
  sm.Add '时间戳', (*) => AddTimestamp(obj)
  sm.Add '窗口阴影', (*) => AddFrameShadow(obj)
  m.Add '操作', sm
  m.Add
  m.Add '存入剪贴板', (*) => SaveToClipBoard(obj.Hwnd)
  m.Add '图像另存为...', (*) => SaveToFileEx(obj.Hwnd)
  m.Add
  m.Add '关闭并存入剪贴板', (*) => SaveToClipBoard(obj.Hwnd, true)
  m.Add '关闭并保存到默认组', (*) => SaveToFileEx(obj.Hwnd, cfg.defaultSavePath, , true)
  m.Add
  sm := Menu()
  Extend(sm, obj.Hwnd)
  sm.Add
  sm.Add '新建分组', (*) => CreateGroup(obj.Hwnd)
  m.Add '存入组', sm
  sm := Menu()
  sm.Add '缩放: ' obj.ZoomLevel, noop
  sm.Add '阴影: ' (obj.HasShadow ? 'true' : 'false'), noop
  sm.Add FormatTime(obj.CreateTime, 'yyyyMMdd_HHmmss'), noop
  m.Add
  m.Add obj.SizeW ' x ' obj.SizeH, sm
  m.Show()
}

OnMessage(0x0207, OnMBtnDown)

OnMBtnDown(*) {
  MouseGetPos(, , &hwnd)
  if not GuiFromHwnd(hwnd) is PasteGui
    return
  SaveToClipBoard(Hwnd, true)
}

#Include ../core/Hook.ahk

AddTimestamp(g) {
  if g.HasTimestamp {
    return
  }
  Hook._Exec(Events.OnTimestampGenerate, g)
  g.SetHasTimestamp(true)
}

AddFrameShadow(g) {
  if g.HasShadow {
    return
  }
  FrameShadow(g.Hwnd)
  g.SetHasShadow(true)

  FrameShadow(hwnd) {
    enabled := 0
    DllCall("dwmapi\DwmIsCompositionEnabled", "int*", &enabled)
    if !enabled {
      DllCall("SetClassLong", "uint", hwnd, "int", -26, "int", 0x20000)
    } else {
      bf := Buffer(4)
      NumPut('uint', -1, bf)
      DllCall("dwmapi\DwmSetWindowAttribute", "ptr", hwnd, "uint", 2, "int*", 2, "uint", 4)
      DllCall("dwmapi\DwmExtendFrameIntoClientArea", "ptr", hwnd, "ptr", bf)
    }
  }
}

DestroyGui(g) {
  g.OnDestroy()
  if !g.HasProp('savePath') {
    return
  }
  path := g.savePath
  if FileExist(path) {                          ; Delete local file
    FileDelete(path)
    Tip.ShowTip('已删除本地文件喵~')
    if g.HasProp('id')
      History.DelFile(g.id)
    HistoryGui.FlushCache()
    logger.Info('销毁文件：' path)
  } else {
    Tip.ShowTip('没有找到对应文件喵...')
    logger.Warn('尝试删除不存在的文件')
  }
}

Extend(sm, pass) {
  menuList := [cfs.Get('default'), cfg.groupsList*]
  for v in menuList
    sm.Add v, (itemName, itemPos, myMenu) => SaveToGroup(itemName, pass)
  defaultMenu := cfs.Get('default')
  defaultMenuName := SubStr(defaultMenu, InStr(defaultMenu, '\', , -1) + 1)
  sm.Check(defaultMenuName)
}

CreateGroup(pass) {
  ib := MyInputBox('输入组名:', '新建组', pass)
  if ib.Result = 'Ok' {
    DirCreate(cfg.groupRoot '\' ib.Value)
    groups := cfg.groupsList
    groups.Push(ib.Value)
    cfs.Set('group', groups)
    cfs.Update()
    if ib.checked {
      path := cfg.groupRoot '\' ib.value
      SaveToFileEx(pass, path)
      Tip.ShowTip('创建并保存了喵~')
    } else
      Tip.ShowTip('创建成功喵~')
    logger.Info('创建组：' ib.value)
  }
}

SaveToGroup(groupName, hwnd) {
  path := cfg.groupRoot '\' groupName
  SaveToFileEx(hwnd, path)
  logger.Info('已保存到分组：' groupName)
}